using Microsoft.AspNet.SignalR.Client;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using IGL_Talk_Windows_Desktop.View;
using System;
using System.Collections.ObjectModel;
using System.Windows.Threading;
using System.Linq;
using System.Collections.Generic;
using ChatLibrary.ChatDTOs;


namespace IGL_Talk_Windows_Desktop.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        HubConnection connection;
        IHubProxy myHub;
        ChatView _chatView;
        public ObservableCollection<MessageViewModel> Messages { get; set; }
        public ObservableCollection<UserViewModel> Users { get; set; }
        public List<NotificationView> Notifications { get; set; }

        private string _userName;
        public string UserName
        {
            get { return _userName; }
            set
            {
                _userName = value;
                RaisePropertyChanged(() => UserName);
            }
        }
        private User _currentUser;
        public User CurrentUser
        {
            get { return _currentUser; }
            set
            {
                _currentUser = value;
                RaisePropertyChanged(() => CurrentUser);
            }
        }

        private User _emptyUser;
        public User EmptyUser
        {
            get { return _emptyUser; }
            set
            {
                _emptyUser = value;
                RaisePropertyChanged(() => EmptyUser);
            }
        }
        private string _singleMessage;
        public string SingleMessage
        {
            get { return _singleMessage; }
            set
            {
                _singleMessage = value;
                RaisePropertyChanged(() => SingleMessage);
            }
        }
        private string _errorMessage;
        public string ErrorMessage
        {
            get { return _errorMessage; }
            set
            {
                _errorMessage = value;
                RaisePropertyChanged(() => ErrorMessage);
            }
        }
        private string _notificationMessage;
        public string NotificationMessage
        {
            get { return _notificationMessage; }
            set
            {
                _notificationMessage = value;
                RaisePropertyChanged(() => NotificationMessage);
            }
        }
        private RelayCommand _loginCommand;
        public RelayCommand LoginCommand
        {
            get
            {
                if (_loginCommand == null)
                {
                    _loginCommand = new RelayCommand(() => Login());
                }
                return _loginCommand;
            }
        }
        private RelayCommand _sendMessageCommand;
        public RelayCommand SendMessageCommand
        {
            get
            {
                if (_sendMessageCommand == null)
                {
                    _sendMessageCommand = new RelayCommand(() => SendMessage());
                }
                return _sendMessageCommand;
            }
        }

        private bool _connectionError;

        public bool ConnectionError
        {
            get { return _connectionError; }
            set
            {
                _connectionError = value;
                RaisePropertyChanged(() => ConnectionError);
            }
        }

        public MainViewModel()
        {
            Messages = new ObservableCollection<MessageViewModel>();
            Users = new ObservableCollection<UserViewModel>();
            Notifications = new List<NotificationView>();

            EmptyUser = new User("");
            connection = new HubConnection("http://wujowojtas.azurewebsites.net");

            myHub = connection.CreateHubProxy("ChatHub");
            connection.Start().ContinueWith(task =>
            {
                if (task.IsFaulted)
                {
                    ConnectionError = true;
                    Console.WriteLine("There was an error opening the connection:{0}", task.Exception.GetBaseException());
                }
                else
                {
                    ConnectionError = false;
                    Console.WriteLine("Connected");
                }
            }).Wait();
            if (ConnectionError)
            {
                ShowError("There was an error while connecting to the server. Probably you have problem with connecting to the Internet.");
            }
            else
            {
                ShowNotification("Connected to server. Enter user name to sign in to the chat. ");
            }
        }

        private void Login()
        {
            ChatView Chat = new ChatView();
            this._chatView = Chat;
            Chat.DataContext = this;


            myHub.Invoke<string>("Register", UserName).ContinueWith(task =>
            {
                _chatView.Dispatcher.Invoke(() =>
                    {
                        if (task.IsFaulted)
                        {
                            ShowError("There was an error while registering user. Probably you have problem with connection to the Internet.");
                            Console.WriteLine("There was an error calling send: {0}", task.Exception.Message);
                        }
                        else
                        {
                            CurrentUser = new User(UserName);
                            Chat.Show();
                            CloseLoginView = true;

                            ShowNotification(String.Format("Welcome to IGL Talk. You have been logged in as {0}.", UserName));
                            Messages.Add(new MessageViewModel(new Message(String.Format("Welcome to IGL Talk, {0}!", UserName), DateTime.Now, EmptyUser), true, true));
                            Console.WriteLine("Registered");
                        }
                    }, DispatcherPriority.Normal);
            });

            myHub.On<List<User>>("registered", (users) =>
            {
                _chatView.Dispatcher.Invoke(() =>
                {
                    AddUsers(users);
                }, DispatcherPriority.Normal);
            });

            myHub.On<User, List<User>>("newUserJoined", (newUser, users) =>
            {
                UserJoined(newUser, users);
            });

            myHub.On<Message>("newMessage", (msg) =>
            {
                GetMessages(msg);
            });

            myHub.On<User, List<User>>("userLoggedOut", (user, users) =>
            {
                _chatView.Dispatcher.Invoke(() =>
                {
                    UserViewModel toRemove = Users.Where(u => u.User.Name == user.Name).First();
                    ShowNotification(String.Format("User {0} has left chat.", user.Name));
                    Messages.Add(new MessageViewModel(new Message(String.Format("{0} has left chat.", user.Name), DateTime.Now, EmptyUser), true, true));
                    Users.Remove(toRemove);
                    AddUsers(users);
                }, DispatcherPriority.Normal);
            });
        }
        private void SendMessage()
        {
            myHub.Invoke<string[]>("SendMessage", new[] { UserName, SingleMessage }).ContinueWith(task =>
            {
                _chatView.Dispatcher.Invoke(() =>
                    {
                        if (task.IsFaulted)
                        {

                            ShowError("There was an error while sending message. Probably you have a problem with connection to the Internet.");

                            Console.WriteLine("There was an error calling send: {0}", task.Exception.GetBaseException());
                        }
                    }, DispatcherPriority.Normal);
            });
            SingleMessage = "";
        }
        public void GetMessages(Message message)
        {
            _chatView.Dispatcher.Invoke(() =>
            {
                Messages.Add(new MessageViewModel(message, true, false));
                System.Media.SystemSounds.Beep.Play();
                foreach (var m in Messages)
                {
                    if (m.Message != message)
                    {
                        m.IsNew = false;
                    }
                }
            }, DispatcherPriority.Normal);

        }
        private void UserJoined(User newUser, List<User> users)
        {
            _chatView.Dispatcher.Invoke(() =>
            {
                if (newUser != CurrentUser)
                {
                    Messages.Add(new MessageViewModel(new Message(String.Format("{0} has joined chat.", newUser.Name), DateTime.Now, EmptyUser), true, true));
                    ShowNotification(String.Format("New user, {0}, has joined chat.", newUser.Name));
                }
                AddUsers(users);
            }, DispatcherPriority.Normal);
        }
        private void AddUsers(List<User> users)
        {
            foreach (var user in users)
            {
                var userVM = new UserViewModel(user, UserName == user.Name);
                if (!Users.Contains(Users.FirstOrDefault(u => u.User.Name == user.Name)))
                {
                    Users.Add(userVM);
                }
            }
        }

        private void ShowNotification(string NotificationMsg)
        {
            var NotifView = new NotificationView();
            //okno ustawia sie jak chce
            int top = (Convert.ToInt32(NotifView.MaxHeight)) * Notifications.Count();
            Notifications.Add(NotifView);
            NotifView.Left = System.Windows.SystemParameters.PrimaryScreenWidth - NotifView.Width - 10;
            NotificationViewModel NotifViewModel = new NotificationViewModel(NotificationMsg, top);
            NotifView.DataContext = NotifViewModel;
            NotifView.Show();
        }

        private void ShowError(string ErrorMsg)
        {
            var ErrorView = new ErrorView();
            ErrorMessage = ErrorMsg;
            ErrorView.DataContext = this;
            ErrorView.Show();
        }

        #region closing
        private bool? _closeLoginView;
        public bool? CloseLoginView
        {
            get { return _closeLoginView; }
            set
            {
                _closeLoginView = value;
                RaisePropertyChanged(() => CloseLoginView);
            }
        }
        private bool? _closeChatView;
        public bool? CloseChatView
        {
            get { return _closeChatView; }
            set
            {
                _closeChatView = value;
                RaisePropertyChanged(() => CloseChatView);
            }
        }
        private RelayCommand _closeWindowCommand;
        public RelayCommand CloseWindowCommand
        {
            get
            {
                if (_closeWindowCommand == null)
                {
                    _closeWindowCommand = new RelayCommand(() => CloseWindow());
                }
                return _closeWindowCommand;
            }
        }
        private void CloseWindow()
        {
            CloseLoginView = true;
        }
        private RelayCommand _logoutCommand;
        public RelayCommand LogoutCommand
        {
            get
            {
                if (_logoutCommand == null)
                {
                    _logoutCommand = new RelayCommand(() => Logout());
                }
                return _logoutCommand;
            }
        }
        private void Logout()
        {
            LoginView loginView2 = new LoginView();
            loginView2.Show();
            connection.Stop();

            ShowNotification(String.Format("You have been logged out.", UserName));
            UserName = "";
            CloseChatView = true;

        }
        #endregion
    }
}